package com.xixibaby.core.mybatis;

import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.baomidou.mybatisplus.extension.injector.AbstractLogicMethod;
import com.xixibaby.core.Assert;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *  left join 嘻嘻 不用写left join了
 * @author : tomj
 * @since : 2019-02-25 10:28
 */
public abstract class JoinMethod extends AbstractLogicMethod {


    protected SqlMethod sqlMethod;
    private boolean logicDelWhere = true;

    public abstract String joinSql(TableInfo tableInfo,SqlMethod sqlMethod);

    //public abstract SqlMethod sqlMethod();

    protected JoinMethod(SqlMethod sqlMethod){
        this.sqlMethod = sqlMethod;
    }
    protected JoinMethod(SqlMethod sqlMethod, boolean logicDelWhere){
        this.sqlMethod = sqlMethod;
        this.logicDelWhere = logicDelWhere;
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        //SqlMethod sqlMethod = ;
        String joinSql = joinSql(tableInfo,this.sqlMethod);
        String sql = String.format(sqlMethod.getSql(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(),
                tableInfo.getTableName(),joinSql, this.sqlWhereEntityWrapper(false,tableInfo));
        SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
        return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, Map.class, tableInfo);
    }

    /**
     * 目标表的字段
     * @return
     */
    protected String[] targetSelectColumns(){
        return new String[]{};
    }

    @Override
    protected String sqlSelectColumns(TableInfo table, boolean queryWrapper) {
        String allSqlSelect = table.getAllSqlSelect();
        String selectColumns = Stream.of(allSqlSelect.split(",")).map(cos -> table.getTableName() + "." + cos + " as " + StringUtils.underlineToCamel(cos)).collect(Collectors.joining(","));
        String choose = SqlScriptUtils.convertChoose(String.format("%s != null and %s != null",
                Constants.WRAPPER, Constants.Q_WRAPPER_SQL_SELECT),
                SqlScriptUtils.unSafeParam(Constants.Q_WRAPPER_SQL_SELECT), selectColumns);

        String[] targets = targetSelectColumns();
        if(Assert.notEmpty(targets)){
            String collect = String.join(",", targets);
            choose += ","  + collect;
        }
        return choose;
    }


    public String getLogicDeleteSql(boolean startWithAnd, boolean deleteValue,TableInfo tableInfo) {
        if (tableInfo.isLogicDelete()) {
            TableFieldInfo field = tableInfo.getFieldList().stream().filter(TableFieldInfo::isLogicDelete).findFirst()
                    .orElseThrow(() -> ExceptionUtils.mpe(String.format("can't find the logicFiled from table {%s}", tableInfo.getTableName())));
            String formatStr = field.isCharSequence() ? "'%s'" : "%s";
            String logicDeleteSql = field.getColumn() + StringPool.EQUALS +
                    String.format(formatStr, deleteValue ? field.getLogicDeleteValue() : field.getLogicNotDeleteValue());
            if (startWithAnd) {
                logicDeleteSql = " AND "+ tableInfo.getTableName()+ "." + logicDeleteSql;
            }
            return logicDeleteSql;
        }
        return StringPool.EMPTY;
    }



    @Override
    protected String sqlWhereEntityWrapper(boolean newLine,TableInfo table) {
        if (table.isLogicDelete()) {
            String sqlScript = table.getAllSqlWhere(true, true, "ew.entity.");
            sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", "ew.entity"), true);
            sqlScript = sqlScript + "\n" + table.getLogicDeleteSql(true, false) + "\n";
            String normalSqlScript = SqlScriptUtils.convertIf(String.format("AND ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.nonEmptyOfNormal"), true);
            normalSqlScript = normalSqlScript + "\n";
            normalSqlScript = normalSqlScript + SqlScriptUtils.convertIf(String.format(" ${%s}", "ew.sqlSegment"), String.format("%s != null and %s != '' and %s", "ew.sqlSegment", "ew.sqlSegment", "ew.emptyOfNormal"), true);
            sqlScript = sqlScript + normalSqlScript;
            sqlScript = SqlScriptUtils.convertChoose(String.format("%s != null", "ew"), sqlScript,
                    table.getLogicDeleteSql(false, false));
            sqlScript = SqlScriptUtils.convertWhere(sqlScript);
            return newLine ? "\n" + sqlScript : sqlScript;
        } else {
            return super.sqlWhereEntityWrapper(newLine, table);
        }
        // 正常逻辑
        //return super.sqlWhereEntityWrapper(s,table);
    }


}
